class SceneImage extends PIXI.Container {
	 constructor(gridSize, scene) { 
		super(); 
		
		this.scene = scene;
		this.gridSize = gridSize;
	 }
	 update() {

		var alpha = 1;	
		if(this.scene.player && this.isCylinder)
			if(this.scene.player.x > this.x - 8 && this.scene.player.x < this.x + this.width &&
			   this.scene.player.y > this.y && this.scene.player.y < this.y + this.height - this.gridSize/2)
				alpha = alpha * 0.7;

		this.alpha = alpha;
	 }
	 
	 get centerPoint() {
		 return {x:this.x+this.width/2,y:this.y+this.height-this.gridSize/2};
	 }
	 
	 set centerPoint(val) {
	 	this.x = val.x - this.width/2;
	 	this.y = val.y - this.height+this.gridSize/2;
	 }
}

class Scene extends PIXI.Container {
	constructor() {
		super();
		this.images = [];
		this.checks = [];

		this._btnZ = new Button("z", {width:18,height:14});
	}

	createNpc(name, style, x, y, dir, func) {
		// 新建NPC
		var npc = L2D.Loader.load(`res/${style}`);
		// 为NPC添加动作
		npc.state = `idea`;
		// 为npcs设置坐标等信息
		npc.direction = dir;
		npc.x = x * currentScene.gridSize;
		npc.y = y * currentScene.gridSize;
		npc.scale = { x:1, y:1 };
		npc.angle = 0;
		npc.tint = {r:1,g:1,b:1};
		npc.isCylinder = true;
		npc.script = func;
		npc.name = name;

		// 添加到实体组件内
		this.addChild(npc);

		return npc;
	}

	createCheck(x, y, w, h, enter, leave) {
		this.checks.push({
			x: x * this.gridSize,
			y: y * this.gridSize,
			width: w * this.gridSize,
			height: h * this.gridSize,
			enter: enter,
			leave: leave
		});
	}
	
	update () {
		if(!this.checksum) return;
		
		// 绘制图形
		for(var i = 0; i < this.images.length; i++)
			this.images[i].update();

		// 检查进入checkpoint
		const x = player.centerPoint.x;
		const y = player.centerPoint.y;
		for(var i = 0; i < this.checks.length; i++) {
			const check = this.checks[i];
			if(x >= check.x && y >= check.y && x <= check.x + check.width && y <= check.y + check.height) {
				// enter
				if(check.entered) continue;

				check.entered = true;
				if(check.enter) check.enter();
			}
			else {
				// leave
				if(check.entered && check.leave) check.leave();

				check.entered = false;
			}
		}
		
		// 更新实体状态
		for(var i = 0; i < this.children.length; i++) {
			const sprite = this.children[i];
			if(sprite.update) sprite.update();
		}
		
		// 计算圆柱实体Z轴
		this.children.sort((a, b) => {
			if(a.isCylinder && b.isCylinder) {
				var aa = a.centerPoint;
				var bb = b.centerPoint;
				if (aa.y > bb.y) return 1;
				if (aa.y < bb.y) return -1;
				if (aa.x > bb.x) return 1;
				if (aa.x < bb.x) return -1;	
			} 
			
			if(a.isCylinder) return 1;
			if(b.isCylinder) return -1;
			return 0;
		});
		
		// 更新实体动作
		var zDis = 10000000;
		this.talker = null;
		for(var i = 0; i < this.children.length; i++) {			
			var enity = this.children[i];
			if(!enity.isCylinder) 
				continue;
					
			// 检查NPC交互
			if(!this.battle) {
				// 查找到距离最近NPC
				if(enity.constructor.name == "Character" && enity.script != null) {
					const xDiff = player.x - enity.x;
					const yDiff = player.y - enity.y;
					const distance = Math.sqrt(xDiff * xDiff + yDiff * yDiff);
					if(distance < this.gridSize * 2) {
						if(distance < zDis) {
							zDis = distance;
							this.talker = enity;
						}
					}
				}
			}
		}

		// 显示交互button
		if(this.talker != null && L2D.UIManager.children.length == 0) {
			this._btnZ.x = this.talker.centerPoint.x - this.gridSize / 2 * 3;
			this._btnZ.y = this.talker.centerPoint.y - this.gridSize / 2 * 3;
			this.addChild(this._btnZ);
		} else {
			this.removeChild(this._btnZ);
		}
		
		// 如果存在战场则更新战场
		if(this.battle) this.battle.update();
	}

	addChild (child) {
		super.addChild(child);
		child.scene = this;
	}

	/**
	 * 寻路
	 * @param {Object} src 当前坐标
	 * @param {Object} dst 目标坐标
	 */
	findPath(src, dst) {
		var path = this.navmesh.findPath(src, dst);
		if(path) path.splice(0,1);
		return path;
	}
	
	/**
	 * 开启战场
	 * @param {Object} loc 战场开启坐标
	 * @param {Object} radius 战场半径
	 */
	fight(loc, radius) {
		// 首先计算开战时范围内所有角色对主角的敌意
		const enemies = [];
		const childrens = [];
		for(var i = 0; i < this.children.length; i++) {
			const child = this.children[i];
			// 如果子项是圆柱体
			if(child.isCylinder) {
				// 计算与战场距离
				const xDiff = child.x - loc.x;
				const yDiff = child.y - loc.y;
				const distance = Math.sqrt(xDiff * xDiff + yDiff * yDiff);
				// 计算距离是否小于战场半径
				if(distance <= radius) {
					// 如果单位存在敌意则加入到战场敌人列表中
					if(child.isEnemy && child.isEnemy(player) && child != player)
						enemies.push(child);

					// 全部加入子集合以便后续触发战场事件
					childrens.push(child);
				}
			}
		}
		
		// 新建战场
		const battle = new Battle(this, enemies);
		// 触发战场事件
		//for(var i = 0; i < childrens.length; i++)
		//	childrens[i].dispatchEvent(new CustomEvent("battle"), { battle });
			
		// 赋予该场景战场属性
		this.battle = battle;
	}
}

function SceneLoader(loader) {
    this.loader = loader;
} 
SceneLoader.prototype = {
    responseType : 'text',
    load : function(buffer, params, enity) {
        var jsonObj = JSON.parse(buffer);

		enity.checksum = jsonObj.Inculde;
		enity.gridSize = jsonObj.GridSize;
		
		const texture = PIXI.Texture.from(`res/${jsonObj.Inculde}`);
		const columns = jsonObj.BitmapWidth / jsonObj.GridSize;
		// 添加地表
		const tileLayers = {};
		
		function getTileLayer(cell) {
			if(!tileLayers[0]) {
				const tiles = new PIXI.Container();
				tiles.zIndex = -1;
				enity.addChild(tiles);
				tileLayers[0] = tiles;				
			}
			
			return tileLayers[0];
		}
		
		var cellStartPosition = jsonObj.CellStartPosition.split(",");
		var cellStartX = parseInt(cellStartPosition[0]);
		var cellStartY = parseInt(cellStartPosition[1]);
		for(var x = 0; x < jsonObj.Cells.length; x++) {
		    const cellArr = jsonObj.Cells[x];
			for(y = 0; y < cellArr.length; y++) {
				const cell = cellArr[y];
				if(cell < 0)
					continue;

				const layer = getTileLayer(cell);
				
				const cellX = (x+cellStartX) * jsonObj.GridSize;
				const cellY = (y+cellStartY) * jsonObj.GridSize;
				const srcX = Math.floor(cell % columns) * jsonObj.GridSize + 1;
		    	const srcY = Math.floor(cell / columns) * jsonObj.GridSize + 1;
				
				// 绘制贴图
				const source = new PIXI.Texture(texture,  { x:srcX, y:srcY, width:jsonObj.GridSize-2, height:jsonObj.GridSize-2 });
				const bunny = new PIXI.Sprite(source);
				bunny.x = cellX;
				bunny.y = cellY;
				bunny.width = jsonObj.GridSize;
				bunny.height = jsonObj.GridSize;
				layer.addChildAt(bunny, 0);
			}
		}
				
		// 添加图形组件
		for(var i = 0; i < jsonObj.Images.length; i++) {
			var jsonImg = jsonObj.Images[i];
			const srcX = (jsonImg.Lower % columns) * jsonObj.GridSize;
			const srcY = Math.floor(jsonImg.Lower / columns) * jsonObj.GridSize;
			const dstX = (jsonImg.Upper % columns) * jsonObj.GridSize + jsonObj.GridSize;
			const dstY = Math.floor(jsonImg.Upper / columns) * jsonObj.GridSize + jsonObj.GridSize;
			const width = dstX - srcX;
			const height = dstY - srcY;
			
			var img = new SceneImage(jsonObj.GridSize, enity);
			
			const source = new PIXI.Texture(texture,  { x:srcX + 1, y:srcY + 1, width:width - 2, height:height - 2 });
			const bunny = new PIXI.Sprite(source);
			bunny.width = width;
			bunny.height = height;
			bunny.scale = { x:jsonImg.Transform.ScaleX, y:jsonImg.Transform.ScaleY };
			bunny.angle = jsonImg.Transform.Angle;
			bunny.tint = {r:jsonImg.Color.R,g:jsonImg.Color.G,b:jsonImg.Color.B};
			
			img.x = jsonImg.Transform.X * jsonObj.GridSize;
			img.y = jsonImg.Transform.Y * jsonObj.GridSize;
			img.width = width;
			img.heght = height;
			img.size = width;
			img.alpha = jsonImg.Color.A/255;
			img.isCylinder = jsonImg.IsCylinder;	
			img.addChild(bunny);
			enity.addChild(img);
		}
		
		// 添加阻挡区域
		var meshPolygonPoints = [];
		var blocks = [];
		var blockStartPosition = jsonObj.GridStartPosition.split(",");
		var blockStartX = parseInt(blockStartPosition[0]);
		var blockStartY = parseInt(blockStartPosition[1]);
		for(var yy = 0; yy < jsonObj.GridMap.length; yy++) {
			const row = jsonObj.GridMap[yy];
			for(var xx = 0; xx < row.length; xx++) {
				const x = (yy+blockStartX)*enity.gridSize;
				const y = (xx+blockStartY)*enity.gridSize;
				const w = enity.gridSize;
				const h = enity.gridSize;
					
				if(row[xx]) 
					meshPolygonPoints.push([{x,y},{x:x+w,y},{x:x+w,y:y+h},{x,y:y+h}]);
				else
					blocks.push({x,y,width:w,height:h});
			}
		}
		enity.blocks = blocks;
		enity.navmesh = new NavMesh(meshPolygonPoints);

		// 加载场景脚本
		currentScene = enity;
		window.require(enity.url + ".fs.js");

    },
	create : function(url) {
	    const scene = new Scene();  
		scene.url = url;
		return scene;
	}
};

L2D.Loader.addMode("gat", new SceneLoader(this));